package com.example.hello.service.impl;

import com.example.hello.common.Result;
import com.example.hello.dto.PasswordUpdateDTO;
import com.example.hello.dto.UserDTO;
import com.example.hello.dto.RegisterDTO;
import com.example.hello.dto.ForgotPasswordDTO;
import com.example.hello.dto.ResetPasswordDTO;
import com.example.hello.dto.IdentityVerificationDTO;
import com.example.hello.dto.PasswordResetDTO;
import com.example.hello.entity.User;
import com.example.hello.mapper.UserMapper;
import com.example.hello.service.UserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Lazy;
import java.util.Date;
import java.util.Random;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

@Service
public class UserServiceImpl implements UserService {

  private static final Logger logger = LogManager.getLogger(UserServiceImpl.class);

  @Autowired
  private UserMapper userMapper;

  private final PasswordEncoder passwordEncoder;

  @Value("${jwt.secret}")
  private String jwtSecret;

  // 验证令牌有效期：30分钟
  private static final long RESET_TOKEN_VALIDITY = 30 * 60 * 1000;

  @Autowired
  public UserServiceImpl(@Lazy PasswordEncoder passwordEncoder) {
    this.passwordEncoder = passwordEncoder;
  }

  @Override
  public User getUserById(Long userId) {
    return userMapper.selectById(userId);
  }

  @Override
  public User getUserByUsername(String username) {
    return userMapper.selectByUsername(username);
  }

  @Override
  public PageInfo<User> getUserList(User user, Integer pageNum, Integer pageSize) {
    PageHelper.startPage(pageNum, pageSize);
    return new PageInfo<>(userMapper.selectUserList(user));
  }

  @Override
  public boolean updateUserInfo(UserDTO userDTO) {
    User user = new User();
    BeanUtils.copyProperties(userDTO, user);
    
    // 如果提供了新的头像URL，更新头像
    if (userDTO.getAvatar() != null && !userDTO.getAvatar().isEmpty()) {
        // 获取当前用户的头像
        User currentUser = userMapper.selectById(userDTO.getUserId());
        String oldAvatar = currentUser.getAvatar();
    }
    
    return userMapper.updateUser(user) > 0;
  }

  @Override
  public boolean updatePassword(Long userId, PasswordUpdateDTO passwordUpdateDTO) {
    // 验证原密码是否正确
    User user = userMapper.selectById(userId);
    if (user == null || !passwordEncoder.matches(passwordUpdateDTO.getOldPassword(), user.getPassword())) {
      return false;
    }

    // 验证两次输入的新密码是否一致
    if (!passwordUpdateDTO.getNewPassword().equals(passwordUpdateDTO.getConfirmPassword())) {
      return false;
    }

    // 更新密码
    String encodedPassword = passwordEncoder.encode(passwordUpdateDTO.getNewPassword());
    return userMapper.updatePassword(userId, encodedPassword) > 0;
  }

  @Override
  public boolean updateUserStatus(Long userId, Integer status) {
    return userMapper.updateStatus(userId, status) > 0;
  }

  @Override
  public User register(RegisterDTO registerDTO) {
    logger.debug("开始注册用户: {}", registerDTO.getUsername());

    // 1. 验证两次密码是否一致
    if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
      logger.warn("用户 {} 注册失败: 两次输入的密码不一致", registerDTO.getUsername());
      throw new RuntimeException("两次输入的密码不一致");
    }

    // 2. 验证用户名是否已存在
    User existUser = userMapper.selectByUsername(registerDTO.getUsername());
    if (existUser != null) {
      logger.warn("用户 {} 注册失败: 用户名已存在", registerDTO.getUsername());
      throw new RuntimeException("用户名已存在");
    }

    // 3. 验证邮箱是否已存在（如果提供了邮箱）
    if (registerDTO.getEmail() != null && !registerDTO.getEmail().isEmpty()) {
      existUser = userMapper.selectByEmail(registerDTO.getEmail());
      if (existUser != null) {
        logger.warn("用户 {} 注册失败: 邮箱已被注册", registerDTO.getUsername());
        throw new RuntimeException("邮箱已被注册");
      }
    }

    // 4. 验证手机号是否已存在（如果提供了手机号）
    if (registerDTO.getPhone() != null && !registerDTO.getPhone().isEmpty()) {
      existUser = userMapper.selectByPhone(registerDTO.getPhone());
      if (existUser != null) {
        logger.warn("用户 {} 注册失败: 手机号已被注册", registerDTO.getUsername());
        throw new RuntimeException("手机号已被注册");
      }
    }

    // 5. 创建用户对象
    User user = new User();
    user.setUsername(registerDTO.getUsername());
    user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
    user.setEmail(registerDTO.getEmail()); // 可以为null
    user.setPhone(registerDTO.getPhone()); // 可以为null
    user.setNickname(registerDTO.getUsername());
    user.setStatus(1); // 修改为激活状态(1)
    user.setRole("user"); // 默认角色为普通用户
    user.setCreatedAt(new Date());
    // 其他字段使用数据库默认值

    // 6. 插入用户数据
    logger.debug("插入用户数据: {}", user.getUsername());
    userMapper.insertUser(user);

    // 7. 返回用户对象（不包含密码）
    user.setPassword(null);
    logger.info("用户 {} 注册成功", user.getUsername());
    return user;
  }

  /**
   * 忘记密码
   * @param forgotPasswordDTO 忘记密码DTO
   * @return 验证码
   */
  @Override
  public String forgotPassword(ForgotPasswordDTO forgotPasswordDTO) {
    logger.debug("开始处理忘记密码请求: {}", forgotPasswordDTO.getEmail());
    
    // 1. 验证邮箱和手机号是否匹配
    User user = userMapper.selectByEmailAndPhone(forgotPasswordDTO.getEmail(), forgotPasswordDTO.getPhone());
    if (user == null) {
        logger.warn("忘记密码失败: 邮箱和手机号不匹配");
        throw new RuntimeException("邮箱和手机号不匹配");
    }
    
    // 2. 生成验证码
    String verificationCode = generateVerificationCode();
    
    // 3. 更新用户验证码
    userMapper.updateVerificationCode(user.getUserId(), verificationCode);
    
    // 4. 在实际应用中，这里应该发送验证码到用户邮箱
    // sendVerificationCodeEmail(user.getEmail(), verificationCode);
    
    logger.info("忘记密码处理成功，已生成验证码: {}", verificationCode);
    return verificationCode;
  }

  /**
   * 重置密码
   * @param resetPasswordDTO 重置密码DTO
   * @return 是否成功
   */
  @Override
  public boolean resetPassword(ResetPasswordDTO resetPasswordDTO) {
    logger.debug("开始处理重置密码请求");
    
    // 1. 验证两次密码是否一致
    if (!resetPasswordDTO.getNewPassword().equals(resetPasswordDTO.getConfirmPassword())) {
        logger.warn("重置密码失败: 两次密码不一致");
        return false;
    }
    
    // 2. 加密新密码
    String encodedPassword = passwordEncoder.encode(resetPasswordDTO.getNewPassword());
    
    // 3. 从当前认证信息中获取用户名
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String username = authentication.getName();
    User user = userMapper.selectByUsername(username);
    
    if (user == null) {
        logger.warn("重置密码失败: 用户不存在");
        return false;
    }
    
    // 4. 更新密码
    int rows = userMapper.updatePassword(user.getUserId(), encodedPassword);
    
    if (rows > 0) {
        logger.info("重置密码成功: {}", username);
        return true;
    } else {
        logger.warn("重置密码失败: 数据库更新失败");
        return false;
    }
  }

  /**
   * 生成6位数字验证码
   * @return 验证码
   */
  private String generateVerificationCode() {
    Random random = new Random();
    int code = 100000 + random.nextInt(900000); // 生成6位数字
    return String.valueOf(code);
  }

  @Override
  public Map<String, Object> verifyIdentity(IdentityVerificationDTO verificationDTO) {
    // 根据用户名查询用户
    User user = userMapper.selectByUsername(verificationDTO.getUsername());
    
    // 验证用户是否存在且邮箱和手机号是否匹配
    if (user == null || !user.getEmail().equals(verificationDTO.getEmail()) 
            || !user.getPhone().equals(verificationDTO.getPhone())) {
        return null;
    }
    
    // 生成验证令牌
    String token = generateResetToken(user.getUserId());
    
    // 返回验证结果
    Map<String, Object> result = new HashMap<>();
    result.put("userId", user.getUserId());
    result.put("verificationToken", token);
    result.put("expiresIn", RESET_TOKEN_VALIDITY / 1000);
    
    logger.info("用户 {} 身份验证成功，生成重置令牌", user.getUsername());
    return result;
  }
  
  @Override
  public Result<Void> resetPassword(PasswordResetDTO resetDTO) {
    try {
        // 解析验证令牌
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes()))
                .build()
                .parseClaimsJws(resetDTO.getVerificationToken())
                .getBody();
        
        // 获取用户ID
        Long userId = claims.get("userId", Long.class);
        
        // 检查令牌是否过期
        if (claims.getExpiration().before(new Date())) {
            logger.warn("重置密码令牌已过期");
            return Result.error(400, "密码令牌已过期");
        }
        
        // 加密新密码
        String encodedPassword = passwordEncoder.encode(resetDTO.getNewPassword());
        
        // 更新密码
        int rows = userMapper.updatePassword(userId, encodedPassword);
        
        if (rows > 0) {
            logger.info("用户 ID {} 密码重置成功", userId);
            return Result.success();
        } else {
            logger.warn("用户 ID {} 密码重置失败", userId);
            return Result.error(400, "重置密码失败");
        }
    } catch (Exception e) {
        logger.error("密码重置失败", e);
        return Result.error(500, "重置密码失败：" + e);
    }
  }
  
  /**
   * 生成密码重置令牌
   * @param userId 用户ID
   * @return JWT令牌
   */
  private String generateResetToken(Long userId) {
    Map<String, Object> claims = new HashMap<>();
    claims.put("userId", userId);
    claims.put("type", "password_reset");
    
    return Jwts.builder()
            .setClaims(claims)
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + RESET_TOKEN_VALIDITY))
            .signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes()), SignatureAlgorithm.HS256)
            .compact();
  }

  @Override
  public boolean resetPassword(String username, String newPassword) {
    User user = userMapper.selectByUsername(username);
    if (user == null) {
        return false;
    }
    
    // 加密新密码
    String encodedPassword = passwordEncoder.encode(newPassword);
    
    // 更新密码 - 使用正确的参数类型
    int rows = userMapper.updatePassword(user.getUserId(), encodedPassword);
    return rows > 0;
  }
}